﻿using System;
using System.CodeDom;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Drawing;
using System.Windows.Forms;
using UIDesigner.DesignContainers;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using UIDesigner.SurfaceProperties;

namespace UIDesigner
{
    public class AFRootControlSerializer : CodeDomSerializer
    {
        private CodeDomSerializer m_objRoot;
        private AFDesignerHost m_objHost;

        public AFRootControlSerializer(CodeDomSerializer objRoot, IDesignerHost objHost)
        {
            m_objRoot = objRoot;
            m_objHost = (AFDesignerHost) objHost;
        }

        public override object Serialize(IDesignerSerializationManager manager, object value)
        {
            UserControl ctrl = (UserControl)value;
            CodeTypeDeclaration objDeclaration;
            object objCode;
            CodeMemberMethod objInitializeMethod = null;
            Dictionary<string, Type> rgFieldTypes = new Dictionary<string,Type>();
            Dictionary<string, string> rgHeaders = new Dictionary<string, string>();
            int x = 0;
            int nInsertAdd = 0;

            if (ctrl == null)
            {
                return null;
            }

            objCode = m_objRoot.Serialize(manager, value);
            objDeclaration = objCode as CodeTypeDeclaration;

            //
            // Field FocusTimer
            //
            CodeMemberField _FocusTimer_field1 = new CodeMemberField();
            _FocusTimer_field1.Attributes = MemberAttributes.Assembly | MemberAttributes.FamilyOrAssembly | MemberAttributes.Private;
            _FocusTimer_field1.Name = "FocusTimer";
            CodeTypeReference _System_Windows_Forms_Timer_type2 = new CodeTypeReference("System.Windows.Forms.Timer");
            _FocusTimer_field1.Type = _System_Windows_Forms_Timer_type2;
            objDeclaration.Members.Add(_FocusTimer_field1);

            foreach (CodeTypeMember objMember in objDeclaration.Members)
            {
                CodeMemberField objField = objMember as CodeMemberField;
                CodeMemberMethod objMethod = objMember as CodeMemberMethod; 

                if (objField != null)
                {
                    if (objField.Type.BaseType == typeof(ObjectControlContainer).FullName)
                    {
                        objField.Type = new CodeTypeReference(typeof(Panel).FullName);
                        rgFieldTypes.Add(objField.Name, typeof(Panel));
                    }
                    else if (objField.Type.BaseType == typeof(Label).FullName)
                    {
                        foreach (ObjectControlContainer ctrlContainer in m_objHost.DesignerLoader.ObjectControlContainers)
                        {
                            ITemplateProvider objProvider = ctrlContainer as ITemplateProvider;

                            if (objProvider != null)
                            {
                                if (objProvider.Header.Name == objField.Name)
                                {
                                    rgHeaders.Add(ctrlContainer.Name + "Header", objField.Name); 
                                }
                            }
                        }
                    }
                }
                else if (objMethod != null && objMember.Name == "InitializeComponent")
                {
                    string strLastProperty = null;
                    bool bLastNotComment = false;

                    objInitializeMethod = objMethod;
                    m_objHost.DataBindingStatements.Clear();

                    CodeAssignStatement _assign36 = new CodeAssignStatement();
                    CodeFieldReferenceExpression _field56 = new CodeFieldReferenceExpression();
                    _field56.FieldName = "ErrorProvider";
                    CodeThisReferenceExpression _this62 = new CodeThisReferenceExpression();
                    _field56.TargetObject = _this62;
                    _assign36.Left = _field56;
                    CodeObjectCreateExpression _new33 = new CodeObjectCreateExpression();
                    CodeTypeReference _System_Windows_Forms_ErrorProvider_type1 = new CodeTypeReference("System.Windows.Forms.ErrorProvider");
                    _new33.CreateType = _System_Windows_Forms_ErrorProvider_type1;
                    CodeFieldReferenceExpression _field57 = new CodeFieldReferenceExpression();
                    _field57.FieldName = "components";
                    CodeThisReferenceExpression _this63 = new CodeThisReferenceExpression();
                    _field57.TargetObject = _this63;
                    _new33.Parameters.Add(_field57);

                    _assign36.Right = _new33;
                    objMethod.Statements.Add(_assign36);

                    foreach (CodeStatement objStatement in objMethod.Statements)
                    {
                        CodeAssignStatement objAssign = objStatement as CodeAssignStatement;
                        CodeExpressionStatement objExpression = objStatement as CodeExpressionStatement;
                        CodeCommentStatement objComment = objStatement as CodeCommentStatement;

                        if (objComment != null)
                        {
                            if (bLastNotComment && strLastProperty != null)
                            {
                                foreach (ObjectControlContainer ctrlContainer in m_objHost.DesignerLoader.ObjectControlContainers)
                                {
                                    foreach (SurfaceButtonEntry objEntry in ctrlContainer.SurfaceButtons)
                                    {
                                        if (objEntry.ButtonControl.Name == strLastProperty)
                                        {
                                            objEntry.CodeInsert = x - 2;
                                            strLastProperty = null;
                                        }
                                    }
                                }
                            }
                            else if (objComment.Comment.Text.Length > 0)
                            {
                                strLastProperty = objComment.Comment.Text;
                                Debug.Write(objComment.Comment.Text + " Properties");
                            }

                            bLastNotComment = false;
                        }
                        else if (objAssign != null)
                        {
                            CodeFieldReferenceExpression objFieldRef = objAssign.Left as CodeFieldReferenceExpression;

                            if (objFieldRef != null)
                            {
                                if (rgFieldTypes.ContainsKey(objFieldRef.FieldName))
                                {
                                    CodeObjectCreateExpression objCreate = objAssign.Right as CodeObjectCreateExpression;
                                    Type objType = rgFieldTypes[objFieldRef.FieldName];

                                    if (objCreate != null)
                                    {
                                        objCreate.CreateType = new CodeTypeReference(objType.FullName);
                                    }
                                }
                            }

                            bLastNotComment = true;
                        }
                        else if (objExpression != null)
                        {
                            CodeMethodInvokeExpression objMethodInvokeExpression = objExpression.Expression as CodeMethodInvokeExpression;

                            if (objMethodInvokeExpression != null)
                            {
                                CodePropertyReferenceExpression objPropertyRef = objMethodInvokeExpression.Method.TargetObject as CodePropertyReferenceExpression;

                                if (objPropertyRef != null && objPropertyRef.PropertyName == "DataBindings")
                                {
                                    m_objHost.DataBindingStatements.Add(objStatement);
                                }
                            }

                            bLastNotComment = true;
                        }

                        x++;
                    }

                    foreach (CodeStatement objBindingStatement in m_objHost.DataBindingStatements)
                    {
                        objMethod.Statements.Remove(objBindingStatement);
                    }

                    CodeAssignStatement _assign2 = new CodeAssignStatement();
                    CodeFieldReferenceExpression _field4 = new CodeFieldReferenceExpression();
                    _field4.FieldName = "FocusTimer";
                    CodeThisReferenceExpression _this4 = new CodeThisReferenceExpression();
                    _field4.TargetObject = _this4;
                    _assign2.Left = _field4;
                    CodeObjectCreateExpression _new2 = new CodeObjectCreateExpression();
                    CodeTypeReference _System_Windows_Forms_Timer_type1 = new CodeTypeReference("System.Windows.Forms.Timer");
                    _new2.CreateType = _System_Windows_Forms_Timer_type1;
                    CodeFieldReferenceExpression _field5 = new CodeFieldReferenceExpression();
                    _field5.FieldName = "components";
                    CodeThisReferenceExpression _this5 = new CodeThisReferenceExpression();
                    _field5.TargetObject = _this5;
                    _new2.Parameters.Add(_field5);

                    _assign2.Right = _new2;
                    objMethod.Statements.Add(_assign2);

                    CodeExpressionStatement _expr3 = new CodeExpressionStatement();
                    CodeMethodInvokeExpression _invoke3 = new CodeMethodInvokeExpression();
                    CodeMethodReferenceExpression _SuspendLayout_method1 = new CodeMethodReferenceExpression();
                    _SuspendLayout_method1.MethodName = "SuspendLayout";
                    CodeThisReferenceExpression _this6 = new CodeThisReferenceExpression();
                    _SuspendLayout_method1.TargetObject = _this6;
                    _invoke3.Method = _SuspendLayout_method1;
                    _expr3.Expression = _invoke3;
                    objMethod.Statements.Add(_expr3);

                    CodeAttachEventStatement _addevent1 = new CodeAttachEventStatement();
                    CodeEventReferenceExpression _event1 = new CodeEventReferenceExpression();
                    _event1.EventName = "Tick";
                    CodeFieldReferenceExpression _field6 = new CodeFieldReferenceExpression();
                    _field6.FieldName = "FocusTimer";
                    CodeThisReferenceExpression _this7 = new CodeThisReferenceExpression();
                    _field6.TargetObject = _this7;
                    _event1.TargetObject = _field6;
                    _addevent1.Event = _event1;
                    CodeObjectCreateExpression _new3 = new CodeObjectCreateExpression();
                    CodeTypeReference _System_EventHandler_type1 = new CodeTypeReference("System.EventHandler");
                    _new3.CreateType = _System_EventHandler_type1;
                    CodeMethodReferenceExpression _method1 = new CodeMethodReferenceExpression();
                    _method1.MethodName = "FocusTimer_Tick";
                    CodeThisReferenceExpression _this8 = new CodeThisReferenceExpression();
                    _method1.TargetObject = _this8;
                    _new3.Parameters.Add(_method1);

                    _addevent1.Listener = _new3;
                    objMethod.Statements.Add(_addevent1);
                }
            }

            foreach (ObjectControlContainer ctrlContainer in m_objHost.DesignerLoader.ObjectControlContainers)
            {
                foreach (SurfaceButtonEntry objEntry in ctrlContainer.SurfaceButtons)
                {
                    Debug.Assert(objEntry.CodeInsert != -1);

                    CodeAttachEventStatement _addevent1 = new CodeAttachEventStatement();
                    CodeEventReferenceExpression _event1 = new CodeEventReferenceExpression();
                    _event1.EventName = "LinkClicked";
                    CodeFieldReferenceExpression _field426 = new CodeFieldReferenceExpression();
                    _field426.FieldName = objEntry.ButtonControl.Name; 
                    CodeThisReferenceExpression _this430 = new CodeThisReferenceExpression();
                    _field426.TargetObject = _this430;
                    _event1.TargetObject = _field426;
                    _addevent1.Event = _event1;
                    CodeObjectCreateExpression _new129 = new CodeObjectCreateExpression();
                    CodeTypeReference _System_Windows_Forms_LinkLabelLinkClickedEventHandler_type1 = new CodeTypeReference("System.Windows.Forms.LinkLabelLinkClickedEventHandler");
                    _new129.CreateType = _System_Windows_Forms_LinkLabelLinkClickedEventHandler_type1;
                    CodeMethodReferenceExpression _method1 = new CodeMethodReferenceExpression();
                    _method1.MethodName = objEntry.ButtonControl.Name + "_LinkClicked";
                    CodeThisReferenceExpression _this431 = new CodeThisReferenceExpression();
                    _method1.TargetObject = _this431;
                    _new129.Parameters.Add(_method1);

                    _addevent1.Listener = _new129;
                    objInitializeMethod.Statements.Insert(objEntry.CodeInsert + nInsertAdd, _addevent1);

                    nInsertAdd++;
                }
            }

            m_objHost.DesignerLoader.InitializeSurfaceStatements.Clear();

            foreach (ObjectControlContainer ctrlContainer in m_objHost.DesignerLoader.ObjectControlContainers)
            {
                ITemplateProvider objTemplateProvider = ctrlContainer as ITemplateProvider;
                CodeStatementCollection rgInitializeSurfaceStatements = new CodeStatementCollection();

                if (objTemplateProvider != null)
                {
                    foreach (XmlDocument objDocument in objTemplateProvider.TemplateDocuments)
                    {
                        m_objHost.DesignerLoader.AddInitializeTemplateCode(objTemplateProvider, objDocument, objDeclaration.Members, objInitializeMethod.Statements, rgInitializeSurfaceStatements, objDeclaration);
                    }

                    m_objHost.DesignerLoader.InitializeSurfaceStatements.Add(ctrlContainer, rgInitializeSurfaceStatements); 
                }
            }

            foreach (KeyValuePair<string, string> objPair in rgHeaders)
            {
                CodeMemberProperty _PrettyNameAttributeLabel_property1 = new CodeMemberProperty();
                _PrettyNameAttributeLabel_property1.Attributes = MemberAttributes.FamilyAndAssembly | MemberAttributes.FamilyOrAssembly | MemberAttributes.Public;
                _PrettyNameAttributeLabel_property1.Name = objPair.Key;
                CodeTypeReference _Label_type1 = new CodeTypeReference("Label");
                _PrettyNameAttributeLabel_property1.Type = _Label_type1;
                _PrettyNameAttributeLabel_property1.HasGet = true;
                CodeMethodReturnStatement _return1 = new CodeMethodReturnStatement();
                CodeFieldReferenceExpression _field28 = new CodeFieldReferenceExpression();
                _field28.FieldName = objPair.Value;
                CodeThisReferenceExpression _this32 = new CodeThisReferenceExpression();
                _field28.TargetObject = _this32;
                _return1.Expression = _field28;
                _PrettyNameAttributeLabel_property1.GetStatements.Add(_return1);

                _PrettyNameAttributeLabel_property1.HasSet = false;
                objDeclaration.Members.Add(_PrettyNameAttributeLabel_property1);
            }

            return objCode;
        }

        public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
        {
            return m_objRoot.Deserialize(manager, codeObject);
        }
    }
}
